﻿using System.Collections.ObjectModel;
using System.Diagnostics;
using KinonekoSoftware.Extensions.Reflections;
using KinonekoSoftware.Foundation.UI.Controls;
using KinonekoSoftware.Platform.Controls;


namespace KinonekoSoftware.Foundation.UI.ViewModels
{
    public abstract class TabbedShell : ShellCore, IViewServiceAmbient, IViewService, IDialogServiceAmbient
    {
        /*
          实现一个非侵入式的标签页框架服务

          1     ->  创建视图模型 (CreateShell)
          2     ->  创建窗口    (Window.Show)
          3     ->  注册服务提供器（OnLoaded）
          4     ->  关联（OnLoaded）
          5


         */
        private readonly ObservableCollection<TabViewModel> _Inboard;
        private readonly ObservableCollection<TabViewModel> _Outboard;
        private readonly Dictionary<string, TabViewModel>   _IdMap;
        private readonly Dictionary<Type, TabViewModel>     _TypeMap;

        private ViewModelBase _current;

        protected TabbedShell()
        {
            _Inboard  = new ObservableCollection<TabViewModel>();
            _Outboard = new ObservableCollection<TabViewModel>();
            _IdMap    = new Dictionary<string, TabViewModel>();
            _TypeMap  = new Dictionary<Type, TabViewModel>();
            Outboard  = new ReadOnlyObservableCollection<TabViewModel>(_Outboard);
            Inboard   = new ReadOnlyObservableCollection<TabViewModel>(_Inboard);
        }

        /// <summary>
        /// 获取起始页的视图模型
        /// </summary>
        /// <returns>返回起始页。</returns>
        protected abstract TabViewModel GetStartupViewModel();

        internal void OpenOutboardTab(TabViewModel target)
        {
            if (target is null)
            {
                return;
            }

            var indexOfOutboard = _Outboard.IndexOf(target);

            if (indexOfOutboard < 0)
            {
                Xplat.Debug($"要打开的标签页(id={target.Id}, hash ={target.GetHashCode()})并不在集合当中！");
                return;
            }

            //
            // 交换位置
            var lastPage = _Inboard[^1];
            _Inboard[^1]               = target;
            _Outboard[indexOfOutboard] = lastPage;

            Current = target;
        }

        protected sealed override void StartBefore()
        {
            ((IViewService)this).GoTo(GetStartupViewModel());
        }


        protected override void StopBefore()
        {
            foreach (var tab in Inboard)
            {
                tab?.Stop();
            }

            foreach (var tab in Outboard)
            {
                tab?.Stop();
            }
            base.StopBefore();
        }

        #region Close

        async Task IViewService.Close(IPageRoot target)
        {
            if (target is null)
            {
                return;
            }

            var target2 = (ViewModelBase)target;


            //
            // TODO:
            // 退出提示
            if (target2.IsChange         &&
                target2.EnableSafetyExit &&
                !await DangerOperation(
                                       TextSR.Dialog_Framework_DangerOperation,
                                       TextSR.Dialog_Framework_CloseTab))
            {
                return;
            }

            if (target2 is TabViewModel tab)
            {
                if (tab.IsSingleton)
                {
                    _TypeMap.Remove(tab.GetType());
                }
                else
                {
                    _IdMap.Remove(tab.Id);


                }

                //
                //
                CloseImpl(tab, tab.IsSingleton);
            }

        }

        private void CloseImpl(TabViewModel target, bool singleton)
        {

            Xplat.RunOnUIThread(() =>
            {

                if (!singleton)
                {
                    //
                    // 停止
                    target.Stop();
                }

                var index  = _Inboard.IndexOf(target);
                var index2 = _Outboard.IndexOf(target);


                if (index > -1)
                {
                    CloseInboardImpl(target, index);
                }
                else if (index < 0 && index2 < 0)
                {
                    return;
                }
                else
                {
                    _Outboard.RemoveAt(index2);
                }

            });
        }

        private void CloseInboardImpl(TabViewModel target, int index)
        {
            var oldTarget = Current;

            //
            // 移除前只有当前界面的话
            if (_Inboard.Count == 1)
            {
                //
                //
                _Inboard.RemoveAt(index);

                //
                //
                ((IViewService)this).GoTo(GetStartupViewModel());
            }
            else
            {
                //
                //
                _Inboard.RemoveAt(index);
            }

            if (_Outboard.Count > 0)
            {
                //
                //
                var first = _Outboard[0];

                //
                //
                _Outboard.RemoveAt(0);

                //
                //
                _Inboard.RemoveAt(index);

                //
                //
                _Inboard.Add(first);
            }


            if (ReferenceEquals(oldTarget, target))
            {
                if (index >= _Inboard.Count - 1)
                {
                    //
                    //
                    _current = _Inboard.LastOrDefault();
                }
                else if (index == 0)
                {
                    //
                    //
                    _current = _Inboard.FirstOrDefault();
                }
                else
                {
                    _current = _Inboard[index];
                }

                //
                // fixed on 2024/2/9
                //
                // 错误调用 Suspend 与 Resume。
                _current?.Resume();

                //
                //
                RaiseUpdated(nameof(Current));
            }
        }


        public void CloseAll()
        {
            foreach (var tab in _Inboard)
            {
                tab.Stop();
            }

            _IdMap.Clear();
            _TypeMap.Clear();
            _Inboard.Clear();
            _Outboard.Clear();

            GoTo(GetStartupViewModel());
        }

        #endregion

        #region Navigation

        bool IViewService.CanGoBack() => false;

        bool IViewService.CanGoForward() => false;

        void IViewService.GoBack() {}

        void IViewService.GoForward() {}

        #endregion

        #region View

        void IViewService.GoTo(IPageRoot instance)
        {
            var vm = instance as ViewModelBase;
            if (vm is not TabViewModel tab)
            {
                var ex = new InvalidCastException($"{vm}的页面视图模型不是基于TabViewModel的");
                GoToException(new InternalErrorPageVM(ex));
                return;
            }

            var context = new PageContext
            {
                Id = Guid.NewGuid().ToString("N"),
            };

            if (!SingletonTypeCheck(vm) && !IdCheck(vm))
            {
                GoTo(tab, context);
            }

        }

        void IViewService.GoTo(IPageRoot instance, IPageContext context)
        {
            var vm = instance as ViewModelBase;
            if (vm is not TabViewModel tab)
            {
                var ex = new InvalidCastException($"{vm}的页面视图模型不是基于TabViewModel的");
                GoToException(new InternalErrorPageVM(ex));
                return;
            }

            if (context is null)
            {
                var ex = new InvalidCastException($"{vm}的页面视图模型参数为空");
                GoToException(new InternalErrorPageVM(ex, typeof(PageContext)));
                return;
            }

            if (!SingletonTypeCheck(vm) && !IdCheck(vm))
            {
                GoTo(tab, (PageContext)context);
            }
        }

        public new void GoTo<T>()
        {
            if (ClassStatic.CreateInstance<T>() is not TabViewModel tab)
            {
                var ex = new InvalidCastException("页面视图模型不是基于TabViewModel的");
                GoToException(new InternalErrorPageVM(ex, typeof(T)));
                return;
            }

            var context = new PageContext
            {
                Id = Guid.NewGuid().ToString("N"),
            };

            if (!SingletonTypeCheck(tab) && !IdCheck(tab))
            {
                GoTo(tab, context);
            }
        }

        public void GoTo<T>(PageContext context)
        {
            if (context is null)
            {
                var ex = new InvalidCastException("PageContext 的页面视图模型参数为空");
                GoToException(new InternalErrorPageVM(ex, typeof(ImplicitArgument)));
                return;
            }

            if (ClassStatic.CreateInstance<T>() is not TabViewModel tab)
            {
                var ex = new InvalidCastException($"{typeof(T).FullName} 页面视图模型不是基于TabViewModel的");
                GoToException(new InternalErrorPageVM(ex, typeof(T)));
                return;
            }

            if (!SingletonTypeCheck(tab) && !IdCheck(tab))
            {
                GoTo(tab, context);
            }
        }


        private bool SingletonTypeCheck(ViewModelBase vm)
        {
            if (vm.IsSingleton && _TypeMap.TryGetValue(vm.GetType(), out var inside))
            {
                if (ReferenceEquals(vm, inside))
                {
                    Current = vm;
                }
                else
                {
                    vm.Stop();
                    Current = inside;
                }
                return true;
            }

            return false;
        }


        private bool IdCheck(ViewModelBase vm)
        {
            if (_IdMap.TryGetValue(vm.Id, out var inside))
            {
                if (ReferenceEquals(vm, inside))
                {
                    //
                    // 同样的容器
                    Current = vm;
                }
                else
                {
                    //
                    //
                    Current = inside;

                    //
                    //
                    vm.Stop();
                }
                return true;
            }

            return false;
        }

        private void GoTo(TabViewModel vm, PageContext context)
        {
            Xplat.RunOnUIThread(() =>
            {
                if (_IdMap.TryGetValue(context.Id, out var target))
                {
                    Current = target;
                    return;
                }

                //
                // 需要在所有操作之前设置ID
                vm.SetId(context.Id);

                //
                // 接受参数
                vm.Receive(context);

                if (vm.IsSingleton && _TypeMap.TryAdd(vm.GetType(), vm))
                {
                    GotoPageAndOverflow(vm);
                }
                else if (_IdMap.TryAdd(vm.Id, vm))
                {
                    GotoPageAndOverflow(vm);
                }

            });
        }

        internal void GotoPageAndOverflow(TabViewModel vm)
        {
            if (_Inboard.Count > 16)
            {
                var lastPage = _Inboard[^1];

                _Inboard.Add(vm);
                _Outboard.Add(lastPage);

#if DEBUG
                var hashCode = lastPage?.GetHashCode() ?? -1;
                Debug.Assert(_Outboard.Any(x => x.GetHashCode() == hashCode));
#endif
            }
            else
            {
                _Inboard.Add(vm);
            }

            Current = vm;
        }

        private void GoToException(ViewModelBase vm)
        {
            Current = vm;
        }

        #endregion

        #region Host

        public void SetHost(ContentHost host)
        {
            if (host is null)
            {
                return;
            }

            ContentHost = host;
        }

        public void SetHost(DialogHost host)
        {
            if (host is null)
            {
                return;
            }

            DialogHost = host;
        }

        public ContentHost ContentHost { get; private set; }
        public DialogHost  DialogHost  { get; private set; }

        #endregion


        public virtual bool ShouldDirectExit => true;

        public int Count => _Inboard.Count + _Outboard.Count;

        public ViewModelBase Current
        {
            get => _current;
            set
            {
                _current?.Suspend();

                SetValue(ref _current, value);


                if (_current is not null && _current.IsInitialized)
                {
                    _current.Resume();
                }
            }
        }

        public ReadOnlyObservableCollection<TabViewModel> Inboard  { get; }
        public ReadOnlyObservableCollection<TabViewModel> Outboard { get; }
    }
}